package io.wongxd.solution.logger

import java.io.PrintWriter
import java.io.StringWriter
import java.net.UnknownHostException
import kotlin.reflect.KProperty

object WLogUtil {

    private var allowed = true
    private var isInitialization = false

    /**
     * 初始化
     * @param tag       标签
     * @param allowed   是否允许打印日志
     * @param modify    是否强制修改之前的初始化配置
     */
    fun init(tag: String, allowed: Boolean, modify: Boolean = false) {
        if (isInitialization && !modify) return
        isInitialization = true
        WLogUtil.allowed = allowed
        val formatStrategy = PrettyFormatStrategy.newBuilder()
            .tag(tag)
            .methodCount(2)
            .build()
        Logger.addLogAdapter(object : AndroidLogAdapter(formatStrategy) {
            override fun isLoggable(priority: Int, tag: String?): Boolean {
                return allowed
            }
        })
    }

    fun init(formatStrategy: PrettyFormatStrategy, allowed: Boolean) {
        WLogUtil.allowed = allowed
        Logger.addLogAdapter(object : AndroidLogAdapter(formatStrategy) {
            override fun isLoggable(priority: Int, tag: String?): Boolean {
                return allowed
            }
        })
    }

    fun d(message: String, vararg args: Any) {
        if (!allowed) return
        Logger.d(message, *args)
    }

    fun d(`object`: Any) {
        if (!allowed) return
        Logger.d(`object`)
    }

    fun e(message: String, vararg args: Any) {
        if (!allowed) return
        Logger.e(null, message, *args)
    }

    fun e(throwable: Throwable, message: String, vararg args: Any) {
        if (!allowed) return
        Logger.e(throwable, message, *args)
    }

    fun i(message: String, vararg args: Any) {
        if (!allowed) return
        Logger.i(message, *args)
    }

    fun v(message: String, vararg args: Any) {
        if (!allowed) return
        Logger.v(message, *args)
    }

    fun w(message: String, vararg args: Any) {
        if (!allowed) return
        Logger.w(message, *args)
    }

    fun wtf(message: String, vararg args: Any) {
        if (!allowed) return
        Logger.wtf(message, *args)
    }

    fun json(json: String) {
        if (!allowed) return
        Logger.json(json)
    }

    fun xml(xml: String) {
        if (!allowed) return
        Logger.xml(xml)
    }

    fun warnTrace(throwable: Throwable, message: String = "") {
        if (!allowed) return
        if (message.isEmpty()) {
            Logger.w(getStackTraceString(throwable))
        } else {
            Logger.w(message, getStackTraceString(throwable))
        }
    }

    fun errorTrace(throwable: Throwable, message: String = "") {
        if (!allowed) return
        if (message.isEmpty()) {
            Logger.e(getStackTraceString(throwable))
        } else {
            Logger.e(message, getStackTraceString(throwable))
        }
    }

    fun getStackTraceString(throwable: Throwable?): String {
        if (throwable == null) {
            return ""
        }
        var t = throwable
        while (t != null) {
            if (t is UnknownHostException) {
                return ""
            }
            t = t.cause
        }
        val sw = StringWriter()
        val pw = PrintWriter(sw)
        throwable.printStackTrace(pw)
        pw.flush()
        return sw.toString()
    }

}

//<editor-fold desc="打印万物">

////'坐标类，嵌套在Location类中'
//data class Coordinate(var x: Int, var y: Int)
////'位置类，嵌套在Person类中'
//data class Location(
//    var country: String,
//    var city: String,
//    var coordinate: Coordinate
//)
//data class Person(
//    var name: String,
//    var age: Int,
//    var locaton: Location? = null
//)
//
//Person("Peter", 16, Location("china", "shanghai", Coordinate(10, 20)))
//    .ofMap()
//    ?.print()
//    .let { Log.v("test", "$it") }
//
////'打印效果如下'
//    {
//    	[age] = 16,
//    	[locaton] =
//              {
//    	          [city] = shanghai,
//    	          [coordinate] =
//                           {
//    	                       [x] = 10,
//    	                       [y] = 20,
//                           },
//    	          [country] = china,
//              },
//    	[name] = Peter,
//    }
//


fun Any.ofMap(): Map<String, Any?>? {
    return this::class.takeIf { it.isData }
        ?.members?.filterIsInstance<KProperty<Any>>()
        ?.map { member ->
            val value = member.call(this).let { v ->
                //'若成员变量是data class，则递归调用ofMap()，将其转化成键值对，否则直接返回值'
                if (v::class.isData) v.ofMap()
                else v
            }
            member.name to value
        }
        ?.toMap()
}

/**
 * 打印 Map，生成结构化键值对子串
 * @param space 行缩进量
 */
fun <K, V> Map<K, V?>.print(space: Int = 0): String {
    //'生成当前层次的行缩进，用space个空格表示，当前层次每一行内容都需要带上缩进'
    val indent = StringBuilder().apply {
        repeat(space) { append(" ") }
    }.toString()
    return StringBuilder("\n${indent}{").also { sb ->
        this.iterator().forEach { entry ->
            //'如果值是 Map 类型，则递归调用print()生成其结构化键值对子串，否则返回值本身'
            val value = entry.value.let { v ->
                (v as? Map<*, *>)?.print("${indent}${entry.key} = ".length) ?: v.toString()
            }
            sb.append("\n\t${indent}[${entry.key}] = $value,")
        }
        sb.append("\n${indent}}")
    }.toString()
}

//</editor-fold>
